1장. 잘 설계된 프로그램이 세상을 뒤흔든다(위대한 소프트웨어는 여기에서 시작된다.)

  1. 1장. 잘 설계된 프로그램이 세상을 뒤흔든다(위대한 소프트웨어는 여기에서 시작된다.)
    1. 쉬운 3단계로 위대한 소프트웨어 만들기
    2. 1.1. 여러분의 소프트웨어가 고객이 원하는 기능을 하도록 만드세요.
    3. 1.3 유지보수와 재사용이 쉬운 디자인을 위해 노력하세요.

쉬운 3단계로 위대한 소프트웨어 만들기

  • 1.1. 여러분의 소프트웨어가 고객이 원하는 기능을 하도록 만드세요.
  • 1.2. 객체지향의 기본 원리를 적용해서 소프트웨어를 유연하게 하세요.
  • 1.3. 유지보수와 재사용이 쉬운 디자인을 위해 노력하세요.

1.1. 여러분의 소프트웨어가 고객이 원하는 기능을 하도록 만드세요.

1.1.1. 릭은 오프라인으로 기타를 팔다가 고객이 원하는 기타를 검색할 수 있도록 프로그램 회사에 의뢰하여 프로그램을 만들게 했습니다.

|

Guitar.javaFindGuitarTester.java
{code}
public class Guitar {
private String serialNumber, builder, model,type,backWood, topWood;
private double price;

public Guitar(String serialNumber, double price, String builder, String model, String type,
String backWood, String topWood){
this.serialNumber = serialNumber;
this.price = price;
this.builder = builder;
this.model = model;
this.type = type;
this.backWood = backWood;
this.topWood = topWood;

}

public String getSerialNumber(){ return serialNumber;}
public double getPrice(){ return price;}
public void setPrice(float newprice){this.price = newprice;}
public String getBuilder(){return builder;}
public String getModel(){ return model;}
public String getType(){ return type;}
public String getBackWood(){ return backWood;}
public String getTopWood(){return topWood;}
}

|

public class FindGuitarTester {

public static void main(String[] args) {

Inventory inventory = new Inventory();
initializeInventory(inventory);

Guitar whatYoungmiLikes = new Guitar("111",0, "fender", "3TS", "electric", "Alder", "Alder");

Guitar guitar = inventory.search(whatYoungmiLikes);

if(guitar != null){
System.out.println("Youngmi, you like this " +
guitar.getBuilder() + " " + guitar.getModel() + guitar.getType() + " " + guitar.getBackWood() +
guitar.getTopWood()+ " you can have it for only $" + guitar.getPrice() );
}else{
System.out.println("Sorry, Youngmi we have nothing");
}
}

// 재고를 목록에 등록
private static void initializeInventory(Inventory inventory){
inventory.addGuitar("111", 222.33, "Fender", "3TS", "electric", "Alder", "Alder");
inventory.addGuitar("222", 104.33, "YAMAHA", "2TS", "electric", "Alder", "Alder");
inventory.addGuitar("333", 155.33, "Fender", "3TS", "electric", "Alder", "Alder");
}
}

|

||Inventory.java||
|

import java.util.*;

public class Inventory {
private List guitars;

public Inventory(){
guitars = new LinkedList();
}

public void addGuitar(String serialNumber, double price, String builder, String model,
String type, String backWood, String topWood){
//기타의 특성을 객체로 만들어서 linkedlist 형식에 add 한다.
Guitar guitar = new Guitar(serialNumber, price, builder,model, type,backWood,topWood);
guitars.add(guitar);
}

//시리얼넘버와 같은 기타의 값을 리턴한다.
public Guitar getGuitar(String serialNumber){
for(Iterator i = guitars.iterator(); i.hasNext();){
Guitar guitar = (Guitar)i.next();

if(guitar.getSerialNumber().equals(serialNumber)){
return guitar;
}
}
return null;
}

public Guitar search(Guitar searchGuitar){
for(Iterator i = guitars.iterator();i.hasNext();){
Guitar guitar = (Guitar)i.next();

//값이 같지 않으면 계속 루프 돈다
String builder = searchGuitar.getBuilder();

if(builder != null && !builder.equals("") && !builder.equals(guitar.getBuilder()))
continue;

String type = searchGuitar.getType();

if(type!=null & !type.equals("") && !type.equals(guitar.getType()))
continue;

String model = searchGuitar.getModel();

if(model != null && !model.equals("")&& !model.equals(guitar.getModel()))
continue;

String backWood = searchGuitar.getBackWood();

if(backWood != null && !backWood.equals("") && !backWood.equals(guitar.getBackWood()))
continue;

String topWood = searchGuitar.getTopWood();

if(topWood != null & !topWood.equals("") && !topWood.equals(guitar.getTopWood()))
continue;

return guitar;
}
return null;
}
}

|



{html}   
<pre>
* 결과는? <font color="#FFFFFF">Sorry, Youngmi we have nothing</font>
* 왜 이런 결과가 나올까요? 
* 그럼 어떻게 고쳐야 할까요?
</pre>                                                                                                                                               
{html}    

 h3. 1.1.2. 문자열 비교 없애기

 !2.JPG!|


||Guitar.java||Inventory.java||FindGuitarTester.java||
|

public class Guitar {
private Builder builder;
private Type type;
private Wood backWood;
private Wood topWood;

public Guitar(String serialNumber, double price, Builder builder,
String model, Type type, Wood backWood, Wood topWood){
this.serialNumber = serialNumber;
this.price = price;
this.builder = builder;
this.model = model;
this.type = type;
this.backWood = backWood;
this.topWood = topWood;
}
}

|

public class Inventory {

public void addGuitar(String serialNumber, double price, Builder builder, String model,
Type type, Wood backWood, Wood topWood){

Guitar guitar = new Guitar(serialNumber, price, builder,model, type,backWood,topWood);
guitars.add(guitar);
}
public Guitar search(Guitar searchGuitar){
for(Iterator i = guitars.iterator();i.hasNext();){
Guitar guitar = (Guitar)i.next();
if(searchGuitar.getBuilder() != guitar.getBuilder())
continue;
String model = searchGuitar.getModel().toLowerCase();
if(model != null && !model.equals(guitar.getModel().toLowerCase()))
continue;
if(searchGuitar.getType() != guitar.getType())
continue;
if(searchGuitar.getBackWood() != guitar.getBackWood())
continue;
if(searchGuitar.getTopWood() != guitar.getTopWood())
continue;
return guitar;
}
return null;
}
}

|

public class FindGuitarTester {

Guitar whatYoungmiLikes = new Guitar("111",0, Builder.FENDER, "3TS", Type.ELECTRIC, Wood.ALDER, Wood.ALDER);

private static void initializeInventory(Inventory inventory){
inventory.addGuitar("111", 222.33, Builder.FENDER, "3TS", Type.ELECTRIC, Wood.ALDER, Wood.ALDER);
inventory.addGuitar("222", 104.33, Builder.YAMAHA, "2TS", Type.ELECTRIC, Wood.ALDER, Wood.ALDER);
inventory.addGuitar("333", 155.33, Builder.FENDER, "3TS", Type.ELECTRIC, Wood.ALDER, Wood.ALDER);
}
}

|

 
 ||Builder.java||Type.java||Wood.java||
|

public enum Builder {
FENDER, YAMAHA;

public String toString(){
switch(this){
case FENDER : return "Fender";
case YAMAHA : return "yamaha";
default : return null;
}
}
}

|

public enum Type {
ACOUSTIC, ELECTRIC;

public String toString(){
switch(this){
case ACOUSTIC : return "Acoustic";
case ELECTRIC : return "Electric";
default: return null;
}
}
}

|

public enum Wood {
MARPLE, ALDER;

public String toString(){
switch(this){
case MARPLE : return "Marple";
case ALDER : return "Alder";
default : return null;
}
}
}

|

* 이 소스에도 뭔가 문제가 있습니다..뭘까요?


h3. 1.1.3.  고객은 여개 중에서 고르고 싶어합니다.  


 !3.JPG!|

||Inventory.java||
|

public class Inventory {

public void addGuitar(String serialNumber, double price, Builder builder, String model,Type type, Wood backWood,
Wood topWood){

Guitar guitar = new Guitar(serialNumber, price, builder,model, type,backWood,topWood);
guitars.add(guitar);
}
public List search(Guitar searchGuitar){
List matchingGuitars = new LinkedList();

for(Iterator i = guitars.iterator();i.hasNext();){
Guitar guitar = (Guitar)i.next();
if(searchGuitar.getBuilder() != guitar.getBuilder())
continue;
String model = searchGuitar.getModel().toLowerCase();
if(model != null && !model.equals(guitar.getModel().toLowerCase()))
continue;
if(searchGuitar.getType() != guitar.getType())
continue;
if(searchGuitar.getBackWood() != guitar.getBackWood())
continue;
if(searchGuitar.getTopWood() != guitar.getTopWood())
continue;
matchingGuitars.add(guitar);
}
return matchingGuitars;
}
}

||

||FindGuitarTester.java||
|

public class FindGuitarTester {

Guitar whatYoungmiLikes = new Guitar("111",0, Builder.FENDER, "3TS", Type.ELECTRIC, Wood.ALDER, Wood.ALDER);
List matchingGuitars = inventory.search(whatYoungmiLikes);

}

|

* 어울리지 않는 객체 타입의 미스터리 (p63)
**  객체는 자신의 이름이 나타내는 일을 해야한다.
**  각 객체는 하나의 개념을 나타내어야 한다.
**  사용되지 않는 속성이 결정적 증거이다. 
         (객체가 값이 없거나 null 인 속성들을 가진 채로 사용되면, 객체가 하나 이상의 일을 하고 있을 가능성이 있다.
         그 속성이 왜 그 객체의 속성이여야 합니까? 분리하세요)



h2. 1.2. 객체지향의 기본 원리를 적용해서 소프트웨어를 유연하게 하세요.

 *  캡슐화를 통해 논리적 그룹으로 나눌 수 있다.
 * 클래스 안의 데이타(data)를 프로그램의 행위(behavior)로부터 분리하는 것처럼, 기타의 속성을 실제 Guitar 객체로부터 분리시킨다.


 !4.JPG!|
 
||Guitar.java||Inventory.java||FindGuitarTester.java||
|

public class Guitar {
private String serialNumber;
private double price;
GuitarSpec spec;

public Guitar(String serialNumber, double price, Builder builder, String model,
Type type, Wood backWood, Wood topWood){
this.serialNumber = serialNumber;
this.price = price;
this.spec = new GuitarSpec(builder, model, type, backWood, topWood);
}
public GuitarSpec getSpec(){
return spec;
}
}

|

public class Inventory {
public List search(GuitarSpec searchSpec){
List matchingGuitars = new LinkedList();

for(Iterator i = guitars.iterator();i.hasNext();){
Guitar guitar = (Guitar)i.next();

GuitarSpec guitarSpec = guitar.getSpec();

if(searchSpec.getBuilder() != guitarSpec.getBuilder())
continue;
String model = searchSpec.getModel().toLowerCase();
if(model != null && !model.equals("") && (!model.equals(guitarSpec.getModel().toLowerCase())))
continue;
if(searchSpec.getType() != guitarSpec.getType())
continue;
if(searchSpec.getBackWood() != guitarSpec.getBackWood())
continue;
if(searchSpec.getTopWood() != guitarSpec.getTopWood())
continue;

matchingGuitars.add(guitar);
}
return matchingGuitars;
}
}

|

public class FindGuitarTester {

public static void main(String[] args) {

GuitarSpec whatYoungmiLikes = new GuitarSpec(Builder.FENDER, "3TS", Type.ELECTRIC, Wood.ALDER, Wood.ALDER);

List matchingGuitars = inventory.search(whatYoungmiLikes);

if(!matchingGuitars.isEmpty()){
for(Iterator i = matchingGuitars.iterator();i.hasNext();){
Guitar guitar = (Guitar)i.next();
GuitarSpec spec = guitar.getSpec();
System.out.println("Youngmi, you like this guitars : " +
spec.getBuilder() + " " + spec.getModel() + " " +
spec.getType() + " " + spec.getBackWood() + " " + spec.getTopWood() +
"\n you can have it for only $" +guitar.getPrice());
}
}else{
System.out.println("Sorry, Youngmi we have nothing");
}
}
}

{code}

1.3 유지보수와 재사용이 쉬운 디자인을 위해 노력하세요.

1.3.1. 릭이 12줄짜리의 기타를 팔고 싶어합니다.

  • 현재 소스에서는 Inventory.java의 addGuitar 메소드에 속성을 추가해야하고 Guitar.java에 생성자도 수정해야된다.
  • 해결방안
    • 기타의 명세를 캡슐화하여 릭의 기타 검색 도구로부터 분리할 필요가 있다.

|

GuitarSpec.javaInventory.java
{code}
public class GuitarSpec {

public GuitarSpec(Builder builder,String model, Type type,int numStrings,
Wood backWood,Wood topWood){
this.builder = builder;
this.model = model;
this.type = type;
this.numStrings = numStrings;
this.backWood = backWood;
this.topWood = topWood;
}
public int getNumStrings(){
return numStrings;
}

public boolean matches(GuitarSpec otherSpec){
if(builder != otherSpec.builder)
return false;

if((model != null) && (!model.equals("")) && (!model.equals(otherSpec.model)))
return false;

if(type != otherSpec.type)
return false;

if(numStrings != otherSpec.numStrings)
return false;

if(backWood != otherSpec.backWood)
return false;

if(topWood != otherSpec.topWood)
return false;

return true;
}
}

|

public class Inventory {

public void addGuitar(String serialNumber, double price, GuitarSpec spec){
//기타의 특성을 객체로 만들어서 링크드리스트 형식에 add 한다.
Guitar guitar = new Guitar(serialNumber, price,spec);
guitars.add(guitar);
}

public List search(GuitarSpec searchSpec){
List matchingGuitars = new LinkedList();

for(Iterator i = guitars.iterator();i.hasNext();){
Guitar guitar = (Guitar)i.next();

if(guitar.getSpec().matches(searchSpec))
matchingGuitars.add(guitar);
}
return matchingGuitars;
}
}

|

 h2. 문서에 대하여
* 최초작성자 : [임영미]
* 최초작성일 : 2008년 06월 13일
* 이 문서는 [Head First Object-Oriented Analysis & Design|http://book.naver.com/bookdb/book_detail.php?bid=2920750]을 정리한 내용 입니다.
* 이 문서는 [오라클클럽|http://www.gurubee.net] [자바 웹개발자 스터디|제3차 자바 웹개발자 스터디] 모임에서 작성하였습니다.
* 이 문서를 다른 블로그나 홈페이지에 게재할 경우에는 출처를 꼭 밝혀 주시면 고맙겠습니다.~^\^